//
// Created by Tony on 2024/7/7.
//

#include "INVOKE_STATIC.h"
#include "../rt_code/Class.h"
#include "../rt_code/ClassTable.h"
#include <memory>

namespace Runtime {

void INVOKE_STATIC::execute(RtData::Frame& frame) {
    auto& curMethod = frame.getMethod();
    shared_ptr<RtCode::Class> curClass = curMethod->getOwnerClass();
    auto& curConstPool = curClass->getConstantPool();
    auto* methodRef = curConstPool.getMethodRef(mIndex);
    auto method = methodRef->resolvedMethod();
    auto clazz = method->getOwnerClass();

    if (!clazz->isInitStarted()) {
        initClass(frame, clazz);
        return;
    }

    if (method->isNative()) {
        auto newFrame = RtData::Frame(nullptr, method);
        auto argSlotCount = method->getArgSlotCount();
        if (argSlotCount > 0) {
            for (int i = argSlotCount - 1; i >= 0; i--) {
                auto slot = frame.popSlot();
                newFrame.setSlot(i, slot);
            }
        }
        shared_ptr<RtCode::ClassTable> classTable = clazz->getClassTable();
        auto nativeMethod =
            classTable->getNativeMethodTable()->get(clazz->getName(), method->getName());
        nativeMethod(newFrame);
        if (!method->isReturnVoid()) {
            auto slot = newFrame.popSlot();
            frame.pushSlot(slot);
        }
        return;
    }

    auto stack = frame.getStack();
    auto newFrame = std::make_shared<RtData::Frame>(stack, method);
    stack->push(newFrame);
    auto argSlotCount = method->getArgSlotCount();
    if (argSlotCount > 0) {
        for (int i = argSlotCount - 1; i >= 0; i--) {
            auto slot = frame.popSlot();
            newFrame->setSlot(i, slot);
        }
    }
}

} // namespace Runtime
